package Java基础.JUC同步工具;

import java.io.IOException;
import java.util.concurrent.*;

/**
 * @Title 通用的Java子线程异常处理方法
 * <p>
 * 更推荐第3种方式，可以方便地在父线程中根据子线程抛出的异常做适当的处理
 * @Author zhengqiang.tan
 * @Date 2021/6/20 3:41 PM
 */
public class ThreadExceptionTest {
    public static void main(String[] args) {
        System.out.println("=== main start ===");

        new Thread(() -> {
            int a = 1 / 0;
        }, "a").start();


        new Thread(() -> {
            // 方法一：子线程中try... catch...
            try {
                throw new IOException("IO Err");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }, "b").start();

        System.out.println("=== main end ===");


        // 演示线程池通过feture获取异常
        ExecutorService executorService = Executors.newFixedThreadPool(8);
        Future future = executorService.submit(new ChildThread());
        try {
            future.get();
        } catch (InterruptedException e) {
            System.out.println(String.format("处理子线程异常1. %s", e));
        } catch (ExecutionException e) {
            System.out.println(String.format("处理子线程异常2. %s", e));
        } finally {
            if (executorService != null) {
                executorService.shutdown();
            }
        }


    }

//    方法三：通过Future的get方法捕获异常（推荐）
//    使用线程池提交一个能获取到返回信息的方法，也就是ExecutorService.submit(Callable)
//    在submit之后可以获得一个线程执行结果的Future对象，而如果子线程中发生了异常，通过future.get()获取返回值时，可以捕获到
//    ExecutionException异常，从而知道子线程中发生了异常。

    static class ChildThread implements Callable<String> {
        public String call() throws Exception {
            System.out.println("do something 1");
            exceptionMethod();
            System.out.println("do something 2");
            return "test result";
        }

        private void exceptionMethod() {
            throw new RuntimeException("ChildThread1 exception");
        }
    }

}
